package com.asiainfo.ai.mirror.util;

import com.asiainfo.mlp.common.core.exception.resource.ResourceNotFoundException;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.http.MediaType;
import org.springframework.web.servlet.mvc.method.annotation.SseEmitter;

import java.io.File;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.RandomAccessFile;
import java.nio.charset.StandardCharsets;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicLong;

/**
 * 构建日志读取工具类
 */
@Slf4j
public final class BuildLogUtils {

    public static SseEmitter getInitSse() {
        return new SseEmitter(1000000L);
    }

    /**
     * 通过sse动态获取日志内容
     *
     * @param filePath   文件路径
     * @param sseEmitter sse
     * @return SseEmitter
     */
    public static SseEmitter getBuildLogBySse(String filePath, SseEmitter sseEmitter) {
        // 超时时间设置为1000s
        File logFile = new File(filePath);
        //定义文件读取的上次位置
        AtomicLong lastTimeFileSize = new AtomicLong();
        //设置线程定时读取日志文件
        ScheduledExecutorService executorService = Executors.newScheduledThreadPool(1);
        try {
            executorService.scheduleWithFixedDelay(() -> {
                RandomAccessFile randomFile;
                //指定文件可读可写
                try {
                    randomFile = new RandomAccessFile(logFile, "rw");
                } catch (FileNotFoundException e) {
                    log.error("日志文件路径={}的文件不存在", filePath, e);
                    throw new ResourceNotFoundException("构建过程日志文件  ", filePath);
                }
                try {
                    //移动文件指针位置
                    randomFile.seek(lastTimeFileSize.get());
                } catch (IOException e) {
                    log.error("日志文件路径={}的文件移动指针位置出现异常", filePath, e);
                    throw new ResourceNotFoundException("构建过程日志文件移动指针位置出现异常", filePath);
                }
                String content;
                while (true) {
                    try {
                        if ((content = randomFile.readLine()) == null) {
                            break;
                        }
                    } catch (IOException e) {
                        log.error("日志文件路径={}的文件读取出现异常", filePath, e);
                        throw new RuntimeException("构建过程日志文件读取出现异常");
                    }
                    content = new String(content.getBytes(StandardCharsets.ISO_8859_1));
                    try {
                        sseEmitter.send(content, MediaType.APPLICATION_JSON);
                    } catch (IOException e) {
                        log.error("日志文件路径={}的文件发送到前端出现异常", filePath, e);
                        throw new RuntimeException("日志文件发送到前端出现异常");
                    }

                    //构建结束标识（成功/失败）
                    if (StringUtils.containsAny(content, "镜像构建失败", "镜像构建流程结束")) {
                        try {
                            sseEmitter.send(SseEmitter.event().name("finish").data("finish"));
                        } catch (IOException e) {
                            log.error("日志文件路径={}的文件发送结束事件出现异常", filePath, e);
                            throw new RuntimeException("日志文件发送结束事件到前端出现异常");
                        }
                        executorService.shutdown();
                        sseEmitter.complete();
                    }
                }
                try {
                    lastTimeFileSize.set(randomFile.length());
                } catch (IOException e) {
                    log.error("获取日志文件路径={}的文件长度出现异常", filePath, e);
                    throw new RuntimeException("获取日志文件的文件长度出现异常");
                }
                try {
                    randomFile.close();
                } catch (IOException e) {
                    log.error("日志文件路径={}的文件读取关闭时出现异常", filePath, e);
                    throw new RuntimeException("日志文件读取关闭时出现异常");
                }
            }, 0, 10, TimeUnit.SECONDS);
        } catch (Exception e) {
            log.error("查询日志出现异常", e);
            //出现异常关闭线程池和服务发送事件
            executorService.shutdown();
            sseEmitter.completeWithError(e);
            throw new RuntimeException("查询日志出现异常");
        }

        //设置超时回调
        sseEmitter.onTimeout(() -> {
            executorService.shutdown();
            log.warn("日志文件路径={}的文件日志查询超时", filePath);
        });
        //设置查询完成回调
        sseEmitter.onCompletion(() -> log.info("日志文件路径={}的文件日志查询完成", filePath));
        return sseEmitter;
    }

}
